package com.tian.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.tian.asyn.SendCodeAsynchronous;
import com.tian.config.RedisConfig;
import com.tian.dto.MessageTemplateDto;
import com.tian.dto.SendCodeReqDto;
import com.tian.enums.ResultCode;
import com.tian.service.MessageTemplateService;
import com.tian.service.SendCodeService;
import com.tian.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.LinkedHashMap;

/**
 * @author tianwc  公众号：java后端技术全栈、面试专栏
 * @version 1.0.0
 * 博客地址：<a href="http://woaijava.cc/">博客地址</a>
 * <p>
 * 发送验证码
 */
@Slf4j
@Service
public class SendCodeServiceImpl implements SendCodeService {
    @Resource
    private RedisConfig redisConfig;
    @Resource
    private MessageTemplateService messageTemplateService;
    @Resource
    private LimiterUtil limiterUtil;
    @Resource
    private SendCodeAsynchronous sendCodeAsynchronous;

    @Override
    public CommonResult<Boolean> sendCode(SendCodeReqDto sendCodeReqDto) {
        String phone = sendCodeReqDto.getPhone();
        int msgTemplateId = sendCodeReqDto.getMsgTemplateId();
        String codeCachePre = sendCodeReqDto.getCacheKeyPre();

        if (StringUtil.isEmpty(phone)) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }
        ParamValidate.isNull(phone, "phone参数为空");
        //同一个手机号码 发送次数限流
        //同一个手机号每分钟 最多只能发5次
        boolean limit = limiterUtil.slidingWindow(RedisConstantPre.MESSAGE_LIMIT_KEY_PRE + phone, (new Date()).getTime(), 60000L, 5);
        if (limit) {
            return CommonResult.failed(ResultCode.SEND_MESSAGE_LIMIT);
        }
        CommonResult<MessageTemplateDto> commonResult = messageTemplateService.queryByMessageType(msgTemplateId);
        if (commonResult.getCode() != ResultCode.SUCCESS.getCode()) {
            log.error("短信模板不存在，msgTemplateId={}", msgTemplateId);
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }

        MessageTemplateDto messageTemplateDto = commonResult.getData();

        //生成随机验证码
        String code = RandomUtil.randomNumbers(6);
        log.info("发送验证码：{}", code);
        //发送验证码
        String template = messageTemplateDto.getTemplate();
        //短信模板中的待替换参数
        LinkedHashMap<String, String> params = new LinkedHashMap<>();
        params.put("code", code);
        // 异步发送短信验证码
        sendCodeAsynchronous.sendCode(template, phone, params);
        //验证码 存到redis中 设置有效期 60秒
        //60秒后需要重现发送
        redisConfig.set(codeCachePre + phone, code, 60);
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public CommonResult<Boolean> codeValid(String phone, String code, String codeCachePre) {

        /**
         * 1:如果 phone 、code 有一个为空，那么就返回验证失败
         * 2：要切 redis 中查询之前 存进去 验证码 。    redis     key=前缀+phone, value= 验证码
         * 3：对比 code 和 redis中验证码 是否 一致，不一致直接发那会 验证码错误。
         * 4：查询远宏户信息
         * 5：组装参数 返回
         *
         */
        if (StringUtil.isEmpty(phone) || StringUtil.isEmpty(code)) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }

        String key = codeCachePre + phone;

        Object codeCache = redisConfig.get(key);

        if (codeCache == null) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }

        if (!code.equals(codeCache.toString())) {
            boolean limit = limiterUtil.slidingWindow(key, (new Date()).getTime(), 60000L, 5);
            if (limit) {
                return CommonResult.failed(ResultCode.SEND_MESSAGE_LIMIT);
            }
        }
        return CommonResult.success(Boolean.TRUE);
    }
}

